﻿// ==================================================
// Copyright 2014 (C) , dotLogix
// Author: Alexander Schill <alexander@schillnet.de>.
// ==================================================

namespace DotLogix {
    #region Using Directives
    using System;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;

    #endregion

    public class AutoSizeSlider : FrameworkElement {
        //Slider
        private Brush _background;
        private Thickness _backgroundMargin;
        private Brush _borderBrush;
        private Pen _borderPen;
        private double _borderRadiusX;
        private double _borderRadiusY;
        private double _borderThickness;
        //Slider_Part
        private Brush _sliderBorderBrush;
        private Pen _sliderBorderPen;
        private double _sliderBorderRadiusX;
        private double _sliderBorderRadiusY;
        private double _sliderBorderThickness;
        private Brush _sliderFill;
        private Thickness _sliderMargin;
        private double _sliderWidth;
        private double _sliderHeight;
        private Brush _valueBorderBrush;
        private Pen _valueBorderPen;
        private double _valueBorderThickness;
        //Slider_Value
        private Brush _valueFill;
        private double _value;
        private double _max=1;
        private double _min;
        private double _valueEndOffset;
        public double ValueEndOffset { get { return _valueEndOffset; } set { _valueEndOffset = value; InvalidateVisual();} }

        public double ScrollStep { get; set; }

        protected override Size MeasureOverride(Size availableSize) { return availableSize; }

        protected override void OnMouseWheel(MouseWheelEventArgs e) {
            var step = ScrollStep == 0 ? (_max - _min) / 20:ScrollStep;
            Value += e.Delta > 0 ? step : -step;
            base.OnMouseWheel(e);
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {
            CaptureMouse();
            base.OnMouseLeftButtonDown(e);
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) {
            ReleaseMouseCapture();
            base.OnMouseLeftButtonUp(e);
        }

        public void EmulateMouseWheelStep(bool positive=true) {
            var step = ScrollStep == 0 ? (_max - _min) / 20 : ScrollStep;
            Value += positive ? step : -step;
        }

        protected override void OnMouseMove(MouseEventArgs e) {
            if(e.LeftButton==MouseButtonState.Released)return;
            var relativeX=e.GetPosition(this).X - _sliderMargin.Left;
            Value = relativeX / (ActualWidth - _sliderMargin.Left - _sliderMargin.Right);
            base.OnMouseMove(e);
        }

        protected override void OnRender(DrawingContext drawingContext) {
            var backgroundPos = new Point(_backgroundMargin.Left, _backgroundMargin.Top);
            var backgroundSize = new Size(ActualWidth - _backgroundMargin.Left - _backgroundMargin.Right,
                ActualHeight - _backgroundMargin.Top - _backgroundMargin.Bottom);
            drawingContext.DrawRoundedRectangle(_background, null, new Rect(backgroundPos, backgroundSize),
                _borderRadiusX, _borderRadiusY);
            
            var sliderPos = new Point(_sliderMargin.Left + ((ActualWidth - _sliderWidth - _sliderMargin.Left - _sliderMargin.Right) * ((_value - _min) / (_max - _min))), _sliderMargin.Top);
            var valueEnd = new Point(sliderPos.X + 0.5 * _sliderWidth+_valueEndOffset, backgroundPos.Y + backgroundSize.Height);
            drawingContext.DrawRoundedRectangle(_valueFill, _valueBorderPen, new Rect(backgroundPos,valueEnd),
                _borderRadiusX, _borderRadiusY);
            drawingContext.DrawRoundedRectangle(_sliderFill, _sliderBorderPen, new Rect(sliderPos,new Size(_sliderWidth,_sliderHeight)),
                _sliderBorderRadiusX, _sliderBorderRadiusY);
            drawingContext.DrawRoundedRectangle(null, _borderPen, new Rect(backgroundPos, backgroundSize),
                _borderRadiusX, _borderRadiusY);
        }

        public double Value {
            get {
                return _value;
            }
            set {
                if(value > _max) {
                    if(_value != _max) {
                        _value = _max;
                        InvalidateVisual();
                    }
                }
                else if(value < _min) {
                    if(_value != _min) {
                        _value = _min;
                        InvalidateVisual();
                    }
                } else {
                    _value = value;
                    InvalidateVisual();
                }
            }
        }

        public double Max { get { return _max; } set { _max = value;InvalidateVisual(); } }
        public double Min { get { return _min; } set { _min = value;InvalidateVisual(); } }

        private void UpdateSliderBorderPen() {
            if(SliderBorderThickness == 0 || _sliderBorderBrush == null)
                _sliderBorderPen = null;
            else
                _sliderBorderPen = new Pen(_sliderBorderBrush, _sliderBorderThickness);
        }

        private void UpdateBorderPen() {
            if(_borderThickness == 0 || _borderBrush == null)
                _borderPen = null;
            else
                _borderPen = new Pen(_borderBrush, _borderThickness);
        }

        private void UpdateMarginPen() {
            if(_valueBorderThickness == 0 || _valueBorderBrush == null)
                _valueBorderPen = null;
            else
                _valueBorderPen = new Pen(_valueBorderBrush, _valueBorderThickness);
        }

        #region Slider_Value Properties
        public double ValueBorderThickness {
            get { return _valueBorderThickness; }
            set {
                _valueBorderThickness = value;
                UpdateMarginPen();
                InvalidateVisual();
            }
        }


        public Brush ValueBorderBrush {
            get { return _valueBorderBrush; }
            set {
                _valueBorderBrush = value;
                UpdateMarginPen();
                InvalidateVisual();
            }
        }


        public Brush ValueFill {
            get { return _valueFill; }
            set {
                _valueFill = value;
                InvalidateVisual();
            }
        }
        #endregion

        #region Slider_Part Properties
        public Thickness SliderMargin {
            get { return _sliderMargin; }
            set {
                _sliderMargin = value;
                InvalidateVisual();
            }
        }

        public double SliderWidth {
            get { return _sliderWidth; }
            set {
                _sliderWidth = value;
                InvalidateVisual();
            }
        }
        public double SliderHeight {
            get { return _sliderHeight; }
            set {
                _sliderHeight = value;
                InvalidateVisual();
            }
        }

        public double SliderBorderRadiusX {
            get { return _sliderBorderRadiusX; }
            set {
                _sliderBorderRadiusX = value;
                InvalidateVisual();
            }
        }

        public double SliderBorderRadiusY {
            get { return _sliderBorderRadiusY; }
            set {
                _sliderBorderRadiusY = value;
                InvalidateVisual();
            }
        }

        public Brush SliderFill {
            get { return _sliderFill; }
            set {
                _sliderFill = value;

                InvalidateVisual();
            }
        }

        public Brush SliderBorderBrush {
            get { return _sliderBorderBrush; }
            set {
                _sliderBorderBrush = value;
                UpdateSliderBorderPen();
                InvalidateVisual();
            }
        }

        public double SliderBorderThickness {
            get { return _sliderBorderThickness; }
            set {
                _sliderBorderThickness = value;
                UpdateSliderBorderPen();
                InvalidateVisual();
            }
        }
        #endregion

        #region Slider_BackgroundProperties
        public double BorderRadiusX {
            get { return _borderRadiusX; }
            set {
                _borderRadiusX = value;
                InvalidateVisual();
            }
        }

        public double BorderRadiusY {
            get { return _borderRadiusY; }
            set {
                _borderRadiusY = value;
                InvalidateVisual();
            }
        }

        public Brush Background {
            get { return _background; }
            set {
                _background = value;
                UpdateSliderBorderPen();
                InvalidateVisual();
            }
        }

        public Brush BorderBrush {
            get { return _borderBrush; }
            set {
                _borderBrush = value;
                UpdateBorderPen();
                InvalidateVisual();
            }
        }

        public double BorderThickness {
            get { return _borderThickness; }
            set {
                _borderThickness = value;
                UpdateBorderPen();
                InvalidateVisual();
            }
        }

        public Thickness BackgroundMargin {
            get { return _backgroundMargin; }
            set {
                _backgroundMargin = value;
                InvalidateVisual();
            }
        }
        #endregion
    }
}